// SendMessage.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "SendMessage.h"
#include "WindowFinder.h"
#include <commctrl.h>
#include "MessageProcessor.h"

#define MAX_LOADSTRING 100

HINSTANCE	hInst;
HWND		hStatic;
HWND		hWndOld;
HBRUSH		brush			=::CreateSolidBrush (RGB(255,255,160));
HCURSOR 	hCurCross;
HCURSOR 	hCurHot;
HCURSOR 	hCurNormal;
HICON		m_hIcon;
HWND		FoundWindowHandle;

int APIENTRY WinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR     lpCmdLine,
	int       nCmdShow)
{

	hInst = hInstance;
	m_hIcon = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAINICON) );

	WNDCLASS wndcls;
	::GetClassInfo(NULL, MAKEINTRESOURCE(32770), &wndcls);

	wndcls.lpszClassName = _T("SendMessage");
	wndcls.hIcon = m_hIcon;

	if (!::RegisterClass(&wndcls))
	{
		MessageBox(NULL, _T("Could not register the class on your machine."), L"Fatal error", MB_OK | MB_ICONINFORMATION );
	}

	::DialogBoxParam (hInstance, MAKEINTRESOURCE (IDD_MAINWIDNOW), NULL, WindowProc, NULL);
	
	return 0;
}

BOOL CALLBACK WindowProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	POINT pt;
	RECT rc;
	static bool bCapture = false;

	static HBITMAP		hBmpCross;
	static HBITMAP		hBmpBlank;

	switch(message)
	{
	case WM_INITDIALOG:
		{
			hStatic = ::GetDlgItem( hDlg, IDC_CAPTURE );
			hBmpCross = LoadBitmap( hInst, MAKEINTRESOURCE( IDB_CROSS ) );
			hBmpBlank = LoadBitmap( hInst, MAKEINTRESOURCE( IDB_BLANK ) );
			hCurCross = LoadCursor( hInst, MAKEINTRESOURCE( IDC_CROSS_HOT ) );
			hCurNormal = LoadCursor( hInst, MAKEINTRESOURCE( IDC_CROSS_NORMAL ) );
		
			FoundWindowHandle = NULL;

			EnableWindow( GetDlgItem(hDlg, IDC_HIGHLIGHT_WINDOW), FALSE);
			return TRUE;
		}	
		break;

	case WM_CLOSE:
		DestroyWindow( hDlg );
		break;

	case WM_DESTROY:
		PostQuitMessage( 0 );
		break;

	case WM_LBUTTONDOWN:
		pt.x = MAKEPOINTS(lParam).x;
		pt.y = MAKEPOINTS(lParam).y;
		::ClientToScreen( hDlg, &pt );

		::GetWindowRect( hStatic, &rc );

		if( ::PtInRect( &rc, pt ))
		{
			::SetCursor( hCurCross );
			::SendMessage( hStatic, STM_SETIMAGE, IMAGE_BITMAP, (long)hBmpBlank );
			::SetCapture( hDlg );
			bCapture = true;
		}
		break;

	case WM_LBUTTONUP:
	case WM_KILLFOCUS:
		if(bCapture)
		{
			if( hWndOld )
				WindowFinder::HighlightWindow( hWndOld, FALSE );
			hWndOld = NULL;

			::SetCursor( hCurNormal );
			::SendMessage( hStatic, STM_SETIMAGE, IMAGE_BITMAP, (long)hBmpCross );
			::ReleaseCapture();
			bCapture = false;
		}
		break;

	case WM_MOUSEMOVE:
		if(bCapture)
		{
			pt.x = MAKEPOINTS(lParam).x;
			pt.y = MAKEPOINTS(lParam).y;
			::ClientToScreen( hDlg, &pt );
			
			RECT window;
			::GetWindowRect( hDlg, &window );

			if(!PtInRect( &window, pt )) WindowFinder::OnMouseMove( hDlg, pt );
		}
		break;

	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
		case ID_FILE_EXIT:
			DestroyWindow( hDlg );
			break;

		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hDlg, About);
			break;

		case IDC_HIGHLIGHT_WINDOW:
			if(FoundWindowHandle != NULL)
				WindowFinder::HighlightWindow( FoundWindowHandle, TRUE );
			break;

		case IDC_WINDOWSMESSAGE:
			if(HIWORD( wParam ) == CBN_SELCHANGE )
			{
				LPWSTR input = NULL;
				::GetDlgItemText( hDlg, IDC_WINDOWSMESSAGE, input, 128 );
			}
			break;
		}
		break;
	}
	return FALSE;
}

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

#pragma region WindowFinder Class

void WindowFinder::OnMouseMove( HWND hDlg, POINT &pt )
{
	HWND hWnd = WindowFinder::SmallestWindowFromPoint (pt);

	if (hWndOld == hWnd) return;	// prevent flickering
	if(hWndOld) 
		WindowFinder::HighlightWindow(hWndOld,FALSE);
	WindowFinder::HighlightWindow(hWnd,TRUE);

	hWndOld = hWnd;
	FoundWindowHandle = hWnd;

	EnableWindow( GetDlgItem(hDlg, IDC_HIGHLIGHT_WINDOW), TRUE );

	_TCHAR ch[128];

	_stprintf_s (ch, __TEXT("0x%08X"), hWnd);
	::SetDlgItemText( hDlg, IDC_WINDOW_HANDLE, ch ); // window handle

	::GetClassName (hWnd, ch, 128);
	::SetDlgItemText( hDlg, IDC_WINDOW_CLASS, ch);      // class name

	SendMessage( hWnd, WM_GETTEXT, 128, (LPARAM)ch );
	::SetDlgItemText( hDlg, IDC_WINDOW_NAME, ch );

}

HWND WindowFinder::SmallestWindowFromPoint( const POINT point )
{
	RECT rect, rcTemp;
	HWND hParent, hWnd, hTemp;

	hWnd = ::WindowFromPoint( point );
	if( hWnd != NULL )
	{
		::GetWindowRect( hWnd, &rect );
		hParent = ::GetParent( hWnd );

		if( hParent != NULL )
		{
			// Search down the Z-Order
			hTemp = hWnd;
			do{
				hTemp = ::GetWindow( hTemp, GW_HWNDNEXT );

				// Search window contains the point, hase the same parent, and is visible?
				::GetWindowRect( hTemp, &rcTemp );
				if(::PtInRect(&rcTemp, point) && ::GetParent(hTemp) == hParent && ::IsWindowVisible(hTemp))
				{
					// Is it smaller?
					if(((rcTemp.right - rcTemp.left) * (rcTemp.bottom - rcTemp.top)) < ((rect.right - rect.left) * (rect.bottom - rect.top)))
					{
						// Found new smaller window!
						hWnd = hTemp;
						::GetWindowRect(hWnd, &rect);
					}
				}
			}while( hTemp != NULL );
		}
	}

	return hWnd;
}

void WindowFinder::HighlightWindow( HWND hwnd, BOOL fDraw )
{
#define DINV                3
	HDC hdc;
	RECT rc;
	BOOL bBorderOn;
	bBorderOn = fDraw;

	if (hwnd == NULL || !IsWindow(hwnd))
		return;

	hdc = ::GetWindowDC(hwnd);
	::GetWindowRect(hwnd, &rc);
	::OffsetRect(&rc, -rc.left, -rc.top);

	if (!IsRectEmpty(&rc))
	{
		PatBlt(hdc, rc.left, rc.top, rc.right - rc.left, DINV,  PATINVERT);
		PatBlt(hdc, rc.left, rc.bottom - DINV, DINV,
			-(rc.bottom - rc.top - 2 * DINV), DSTINVERT);
		PatBlt(hdc, rc.right - DINV, rc.top + DINV, DINV,
			rc.bottom - rc.top - 2 * DINV, DSTINVERT);
		PatBlt(hdc, rc.right, rc.bottom - DINV, -(rc.right - rc.left),
			DINV, DSTINVERT);
	}

	::ReleaseDC(hwnd, hdc);
}

#pragma endregion WindowFinder Class


#pragma region MessageProcessor

#pragma endregion MessageProcessor